<template>
  <div class="menu-container">
    <el-card>
      <template #header>
        <div class="card-header">
          <span>菜单管理</span>
          <el-button type="primary" @click="handleAdd" v-permission="'system:menu:add'">新增菜单</el-button>
        </div>
      </template>
      <el-input v-model="menuName" placeholder="请输入菜单名称"
                style="width: 200px; margin-bottom: 10px; margin-right: 10px"/>
      <el-button type="danger" style="margin-bottom: 10px;" @click="search">搜索</el-button>
      <el-button type="info" style="margin-bottom: 10px;" @click="reSet">重置</el-button>
      <el-table :data="menuList" style="width: 100%" row-key="id" :key="tableKey" border>
        <el-table-column type="index" label="序号" width="60" align="center" fixed/>
        <el-table-column prop="name" label="菜单名称" width="200" align="center"/>
        <el-table-column prop="icon" label="图标" width="100" align="center">
          <template #default="{ row }">
            <el-icon v-if="getIconComponent(row.icon)">
              <component :is="getIconComponent(row.icon)"/>
            </el-icon>
          </template>
        </el-table-column>
        <el-table-column prop="orderNum" label="排序" width="80" align="center"/>
        <el-table-column prop="perms" label="权限标识" align="center"/>
        <el-table-column prop="path" label="路由地址" align="center"/>
        <el-table-column prop="component" label="组件路径" align="center"/>
        <el-table-column prop="type" label="类型" width="80" align="center">
          <template #default="{ row }">
            <el-tag v-if="row.type === 'M'">目录</el-tag>
            <el-tag v-else-if="row.type === 'C'" type="success">菜单</el-tag>
            <el-tag v-else-if="row.type === 'F'" type="warning">按钮</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="status" label="状态" width="80" align="center">
          <template #default="{ row }">
            <el-tag :type="row.status === 1 ? 'success' : 'danger'">
              {{ row.status === 1 ? '启用' : '禁用' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="200" align="center">
          <template #default="{ row }">
            <el-button type="primary" link @click="handleEdit(row)" v-permission="'system:menu:edit'">编辑</el-button>
            <el-button type="primary" link @click="handleDelete(row)" v-permission="'system:menu:delete'">删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="pageNum"
          :page-sizes="[10, 20, 50, 100]"
          :page-size="pageSize"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
      />
    </el-card>

    <!-- 新增/编辑菜单对话框 -->
    <el-dialog
        v-model="dialogVisible"
        :title="dialogType === 'add' ? '新增菜单' : '编辑菜单'"
        width="500px"
    >
      <el-form
          ref="formRef"
          :model="form"
          :rules="rules"
          label-width="100px"
      >
        <el-form-item label="上级菜单">
          <el-tree-select
              v-model="form.parentId"
              :data="menuOptions"
              :props="{ label: 'name', value: 'id' }"
              placeholder="请选择上级菜单"
              clearable
              check-strictly
              node-key="id"
              :default-expanded-keys="defaultExpandedKeys"
          />
        </el-form-item>
        <el-form-item label="菜单类型" prop="type">
          <el-radio-group v-model="form.type">
            <el-radio label="M">目录</el-radio>
            <el-radio label="C">菜单</el-radio>
            <el-radio label="F">按钮</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="菜单名称" prop="name">
          <el-input v-model="form.name" placeholder="请输入菜单名称"/>
        </el-form-item>
        <el-form-item label="图标" prop="icon" v-if="form.type !== 'F'">
          <el-input v-model="form.icon" placeholder="请输入图标名称"/>
        </el-form-item>
        <el-form-item label="排序" prop="orderNum">
          <el-input-number v-model="form.orderNum" :min="0" :max="999"/>
        </el-form-item>
        <el-form-item label="路由地址" prop="path" v-if="form.type !== 'F'">
          <el-input v-model="form.path" placeholder="请输入路由地址"/>
        </el-form-item>
        <el-form-item label="组件路径" prop="component" v-if="form.type === 'C'">
          <el-input v-model="form.component" placeholder="请输入组件路径"/>
        </el-form-item>
        <el-form-item label="权限标识" prop="perms" v-if="form.type !== 'M'">
          <el-input v-model="form.perms" placeholder="请输入权限标识"/>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="form.status">
            <el-radio :label="1">启用</el-radio>
            <el-radio :label="0">禁用</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import {ref, onMounted} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import {getAllMenuList, getMenuPage, addMenu, updateMenu, deleteMenu} from '@/api/menu'
import * as ElIcons from '@element-plus/icons-vue'

interface MenuItem {
  id?: number;
  parentId?: number;
  name: string;
  path?: string;
  component?: string;
  perms?: string;
  type?: 'M' | 'C' | 'F';
  icon?: string;
  orderNum?: number;
  status?: number;
  children?: MenuItem[];
}

interface ApiResponse<T> {
  code: number;
  msg: string;
  data: T;
}

interface PageResult<T> {
  records: T[];
  total: number;
  size: number;
  current: number;
  pages: number;
}


const menuList = ref<MenuItem[]>([])
const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)
const dialogVisible = ref(false)
const dialogType = ref<'add' | 'edit'>('add')
const formRef = ref()
const menuOptions = ref<MenuItem[]>([])
const defaultExpandedKeys = ref<number[]>([])
const tableKey = ref(0)

const form = ref<MenuItem>({
  id: undefined,
  parentId: 0,
  name: '',
  path: '',
  component: '',
  perms: '',
  type: 'M',
  icon: '',
  orderNum: 0,
  status: 1
})

const rules = {
  name: [{required: true, message: '请输入菜单名称', trigger: 'blur'}],
  type: [{required: true, message: '请选择菜单类型', trigger: 'change'}],
  path: [{required: true, message: '请输入路由地址', trigger: 'blur'}],
  component: [{required: true, message: '请输入组件路径', trigger: 'blur'}],
  perms: [{required: true, message: '请输入权限标识', trigger: 'blur'}]
}

// 辅助函数：获取图标组件
const getIconComponent = (iconName: string | undefined) => {
  if (!iconName) return null;

  // 尝试将 kebab-case 转换为 PascalCase (如 'tree-table' -> 'TreeTable')
  let formattedIconName = iconName.replace(/-(\w)/g, (_, c) => c.toUpperCase());
  formattedIconName = formattedIconName.charAt(0).toUpperCase() + formattedIconName.slice(1);

  // 检查是否存在对应的 Element Plus 图标组件
  const iconComponent = (ElIcons as any)[formattedIconName];
  if (iconComponent) {
    return iconComponent;
  }

  // 如果没有找到，返回 null (或者可以返回一个默认图标组件)
  console.warn(`Icon component not found for: ${iconName}`);
  return null;
};
const search = async () => {
  await fetchMenuData()
}
const reSet = async () => {
  menuName.value = ''
  await fetchMenuData()
}
const getAllMenuIds = (menus: MenuItem[]): number[] => {
  let ids: number[] = [];
  menus.forEach(menu => {
    if (menu.id !== undefined) {
      ids.push(menu.id);
    }
    if (menu.children && menu.children.length > 0) {
      ids = ids.concat(getAllMenuIds(menu.children));
    }
  });
  return ids;
}
const menuName = ref<string>('')
const fetchMenuData = async () => {
  const pageRes: ApiResponse<PageResult<MenuItem>> = await getMenuPage({
    pageNum: pageNum.value,
    pageSize: pageSize.value,
    menuName: menuName.value,
  })
  if (pageRes.code === 200) {
    menuList.value = pageRes.data.records;
    total.value = pageRes.data.total;
    tableKey.value++;
  }

  const allMenuRes: ApiResponse<MenuItem[]> = await getAllMenuList();
  if (allMenuRes.code === 200) {
    menuOptions.value = [{id: 0, name: '主目录', children: allMenuRes.data}]
    defaultExpandedKeys.value = getAllMenuIds(allMenuRes.data);
    defaultExpandedKeys.value.push(0);
  }
}

const handleSizeChange = (val: number) => {
  pageSize.value = val
  fetchMenuData()
}

const handleCurrentChange = (val: number) => {
  pageNum.value = val
  fetchMenuData()
}

const resetForm = () => {
  form.value = {
    id: undefined,
    parentId: 0,
    name: '',
    path: '',
    component: '',
    perms: '',
    type: 'M',
    icon: '',
    orderNum: 0,
    status: 1
  }
}

const handleAdd = () => {
  dialogType.value = 'add'
  resetForm()
  dialogVisible.value = true
}

const handleEdit = (row: any) => {
  dialogType.value = 'edit'
  form.value = {...row}
  dialogVisible.value = true
}

const handleDelete = (row: any) => {
  ElMessageBox.confirm('确认要删除该菜单吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async () => {
    const res: ApiResponse<any> = await deleteMenu(row.id as number)
    if (res.code === 200) {
      ElMessage.success('删除成功')
      fetchMenuData()
    } else {
      ElMessage.error(res.msg || '删除失败')
    }
  }).catch(() => {
  })
}

const handleSubmit = async () => {
  if (!formRef.value) return
  await formRef.value.validate(async (valid: boolean) => {
    if (valid) {
      const api = dialogType.value === 'add' ? addMenu : updateMenu
      const res: ApiResponse<any> = await api(form.value as MenuItem)
      if (res.code === 200) {
        ElMessage.success(dialogType.value === 'add' ? '新增成功' : '编辑成功')
        dialogVisible.value = false
        fetchMenuData()
      } else {
        ElMessage.error(res.msg || (dialogType.value === 'add' ? '新增失败' : '编辑失败'))
      }
    }
  })
}

onMounted(async () => {
  await fetchMenuData()
})
</script>

<style scoped>
.menu-container {
  padding: 20px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.el-pagination {
  margin-top: 20px;
  justify-content: flex-end;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
</style>
